////////////////////////////////////////////////////////////////////////////
//
//  Immense Engine Source File.
//  Copyright (C), Indloon 2012
// -------------------------------------------------------------------------
//  File name:   ieMathRect.h
//  Description: Rect class
//  Created:     8/12/2012 Genert Org
//  Compilers:   Visual C++ 2010 Express
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////
#ifndef __IMMENSEENGINE_MATH_RECT_H
#define __IMMENSEENGINE_MATH_RECT_H

#define LEFT						0
#define TOP							1
#define RIGHT						2
#define BOTTOM						3

/*  1. C L A S S
	=========================================================================== */

class ieRect {
private:
	short			x1;
	short			y1;
	short			x2;
	short			y2;

public:
					ieRect( void );
	explicit		ieRect( const short x1, const short y1, const short x2, const short y2 );

	short			operator [] ( const int index ) const;
	short &			operator [] ( const int index );
	ieRect &		operator = ( const ieRect &rect );
	bool			operator == ( const ieRect &rect ) const;
	bool			operator != ( const ieRect &rect ) const;

	bool			AreEqual( const ieRect &rect ) const;
	void			Set( const short x1, const short y1, const short x2, const short y2 );
	void			SetFloat( const float x1, const float y1, const float x2, const float y2 );
	void			Clear( void );
	bool			IsCleared( void ) const;
	void			Zero( void );
	bool			IsZeroed( void ) const;
	void			AddRect( const ieRect &rect );
	void			AddPoint( const short x, const short y );
	ieRect			Expand( const short size ) const;
	void			ExpandSelf( const short size );
	ieRect			Translate( const short x, const short y ) const;
	void			TranslateSelf( const short x, const short y );
	void			Clip( const ieRect &rect );
	void			Clip( const ieRect &rect1, const ieRect &rect2 );
	void			Combine( const ieRect &rect );
	void			Combine( const ieRect &rect1, const ieRect &rect2 );
	bool			IntersectsRect( const ieRect &rect ) const;
	bool			ContainsPoint( const short x, const short y ) const;
	short			X( void ) const;
	short			Y( void ) const;
	short			Width( void ) const;
	short			Height( void ) const;
	int				Size( void ) const;
};

/*  2. F U N C T I O N S
	=========================================================================== */
	
// -------------------------------------------------------------------------------------------------------------
ILINE ieRect::ieRect( void )
{
    // ...
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieRect::ieRect( const short x1, const short y1, const short x2, const short y2 )
{
	this->x1 = x1;
	this->y1 = y1;
	this->x2 = x2;
	this->y2 = y2;
}
// -------------------------------------------------------------------------------------------------------------
ILINE short ieRect::operator [] ( const int index ) const 
{
	return ( &x1 )[index];
}
// -------------------------------------------------------------------------------------------------------------
ILINE short &ieRect::operator [] ( const int index )
{
	return ( &x1 )[index];
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieRect &ieRect::operator = ( const ieRect &rect )
{
	x1 = rect.x1;
	y1 = rect.y1;
	x2 = rect.x2;
	y2 = rect.y2;

	return *this;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::operator == ( const ieRect &rect ) const 
{
	if( x1 != rect.x1 || y1 != rect.y1 || x2 != rect.x2 || y2 != rect.y2 )
    {
		return false;
	}
	else
	{
		return true;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::operator != ( const ieRect &rect ) const {

	if( x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2 )
	{
		return false;
	}
	else
	{
		return true;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::AreEqual( const ieRect &rect ) const 
{
	if( x1 != rect.x1 || y1 != rect.y1 || x2 != rect.x2 || y2 != rect.y2 )
	{
		return false;
	}
	else
	{
		return true;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Set( const short x1, const short y1, const short x2, const short y2 )
{
	this->x1 = x1;
	this->y1 = y1;
	this->x2 = x2;
	this->y2 = y2;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::SetFloat( const float x1, const float y1, const float x2, const float y2 )
{
	this->x1 = ieMath::FloatToShort( x1 );
	this->y1 = ieMath::FloatToShort( y1 );
	this->x2 = ieMath::FloatToShort( x2 );
	this->y2 = ieMath::FloatToShort( y2 );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Clear( void )
{
	x1 = y1 = 32767;
	x2 = y2 = -32768;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::IsCleared( void ) const 
{
	if( x1 <= x2 || y1 <= y2 )
	{
		return false;
	}
	else
	{
		return true;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Zero( void )
{
	x1 = y1 = 0;
	x2 = y2 = 0;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::IsZeroed( void ) const 
{
	if( x1 != 0 || y1 != 0 ) 
	{
        return false;
	}

    if( x2 != 0 || y2 != 0 )
    {
    	return false;
    }

    return true;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::AddRect( const ieRect &rect )
{
	if( rect.x1 < x1 )
	{
		x1 = rect.x1;
	}

	if( rect.y1 < y1 )
	{
		y1 = rect.y1;
	}

	if( rect.x2 > x2 ) {
		x2 = rect.x2;
	}

	if( rect.y2 > y2 )
	{
		y2 = rect.y2;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::AddPoint( const short x, const short y )
{
	if( x < x1 )
	{
		x1 = x;
	}

	if( y < y1 )
	{
		y1 = y;
	}

	if( x > x2 )
	{
		x2 = x;
	}

	if( y > y2 )
	{
		y2 = y;
	}
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieRect ieRect::Expand( const short size ) const 
{
	return ieRect( x1 - size, y1 - size, x2 + size, y2 + size );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::ExpandSelf( const short size )
{

	x1 -= size;
	y1 -= size;
	x2 += size;
	y2 += size;
}
// -------------------------------------------------------------------------------------------------------------
ILINE ieRect ieRect::Translate( const short x, const short y ) const 
{
	return ieRect( x1 + x, y1 + y, x2 + x, y2 + y );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::TranslateSelf( const short x, const short y )
{
	x1 += x;
	y1 += y;
	x2 += x;
	y2 += y;
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Clip( const ieRect &rect )
{
	x1 = Max( x1, rect.x1 );
	y1 = Max( y1, rect.y1 );
	x2 = Min( x2, rect.x2 );
	y2 = Min( y2, rect.y2 );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Clip( const ieRect &rect1, const ieRect &rect2 )
{
	x1 = Max( rect1.x1, rect2.x1 );
	y1 = Max( rect1.y1, rect2.y1 );
	x2 = Min( rect1.x2, rect2.x2 );
	y2 = Min( rect1.y2, rect2.y2 );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Combine( const ieRect &rect )
{
	x1 = Min( x1, rect.x1 );
	y1 = Min( y1, rect.y1 );
	x2 = Max( x2, rect.x2 );
	y2 = Max( y2, rect.y2 );
}
// -------------------------------------------------------------------------------------------------------------
ILINE void ieRect::Combine( const ieRect &rect1, const ieRect &rect2 )
{
	x1 = Min( rect1.x1, rect2.x1 );
	y1 = Min( rect1.y1, rect2.y1 );
	x2 = Max( rect1.x2, rect2.x2 );
	y2 = Max( rect1.y2, rect2.y2 );
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::IntersectsRect( const ieRect &rect ) const 
{
	if( x1 > rect.x2 || y1 > rect.y2 )
	{
		return false;
	}
	
	if( x2 < rect.x1 || y2 < rect.y1 )
	{
		return false;
	} 

    return true;
}
// -------------------------------------------------------------------------------------------------------------
ILINE bool ieRect::ContainsPoint( const short x, const short y ) const 
{
	if ( x1 > x || y1 > y )
	{
		return false;
	}

	if( x2 < x || y2 < y )
	{
		return false;
	}

	return true;
}
// -------------------------------------------------------------------------------------------------------------
ILINE short ieRect::X( void ) const 
{
	return x1;
}
// -------------------------------------------------------------------------------------------------------------
ILINE short ieRect::Y( void ) const
{
	return y1;
}

ILINE short ieRect::Width( void ) const
{
	if ( x1 > x2 )
	{
		return 0;
	}

	return x2 - x1;
}
// -------------------------------------------------------------------------------------------------------------
ILINE short ieRect::Height( void ) const 
{
	if( y1 > y2 )
	{
		return 0;
	}

	return y2 - y1;
}
// -------------------------------------------------------------------------------------------------------------
ILINE int ieRect::Size( void ) const 
{
	if( x1 > x2 || y1 > y2 )
	{
		return 0;
	}

	return ( x2 - x1 ) * ( y2 - y1 );
}
// -------------------------------------------------------------------------------------------------------------


#endif	// __IMMENSEENGINE_MATH_RECT_H